package com.sita.cfmoto.utils;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.util.Base64;
import android.view.WindowManager;

import com.sita.cfmoto.support.GlobalContext;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BitmapUtils {
    public final static String TAG = BitmapUtils.class.getSimpleName();

    public static ArrayList<Bitmap> getFrames(String path) {
        try {
            ArrayList<Bitmap> bArray = new ArrayList<>();
            bArray.clear();
            MediaMetadataRetriever mRetriever = new MediaMetadataRetriever();
            Map<String, String> headers = new HashMap<>();
            mRetriever.setDataSource(path, headers);

            for (int i = 0; i < 3; i++) {
                bArray.add(mRetriever.getFrameAtTime(1000 * i,
                        MediaMetadataRetriever.OPTION_CLOSEST_SYNC));
            }
            return bArray;
        } catch (Exception e) {
            return null;
        }
    }

    public static Bitmap getSingleFrame(String path) {
        List<Bitmap> frames = getFrames(path);
        Bitmap r = null;
        for (Bitmap f : frames
                ) {
            if (f != null) {
                r = f;
                break;
            }
        }
        return r;
    }

    public static void saveCacheImage(String key, Bitmap bitmap) {
        if (GlobalContext.mMemoryCache.get(key) == null) {
            GlobalContext.mMemoryCache.put(key, bitmap);
        }
    }

    public static Bitmap getCachedImage(String key) {
        Bitmap r = GlobalContext.mMemoryCache.get(key);
        if (r != null) {
            LogUtils.d(TAG, "cache image get ok");
        }
        return r;
    }

    public interface GetFrameListener {
        void success(Bitmap frame);
    }

    public static Bitmap getFrameAsync(String key, GetFrameListener listener) {
        new GetVideoFrameTask(listener).execute(key);
        return null;
    }

    private static class GetVideoFrameTask extends AsyncTask<String, Integer, Bitmap> {
        GetFrameListener listener;

        public GetVideoFrameTask(GetFrameListener listener) {
            this.listener = listener;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            LogUtils.d(TAG, "get frame async ok");
            if (listener != null) {
                listener.success(bitmap);
            }
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            return getSingleFrame(params[0]);
        }

    }

    /**
     * Get a thumbnail bitmap.
     *
     * @param uri
     * @return a thumbnail bitmap
     * @throws java.io.FileNotFoundException
     * @throws java.io.IOException
     */
    public static Bitmap getThumbnail(Context context, Uri uri, int thumbnailSize) throws
            FileNotFoundException, IOException {
        InputStream input = context.getContentResolver().openInputStream(uri);

        BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
        onlyBoundsOptions.inJustDecodeBounds = true;
        onlyBoundsOptions.inDither = true;// optional
        onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;// optional
        BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
        input.close();
        if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1))
            return null;

        int originalSize = (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth) ? onlyBoundsOptions.outHeight : onlyBoundsOptions.outWidth;

        double ratio = (originalSize > thumbnailSize) ? (originalSize / thumbnailSize) : 1.0;

        BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
        bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio);
        bitmapOptions.inDither = true;// optional
        bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;// optional
        input = context.getContentResolver().openInputStream(uri);
        Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
        input.close();
        return bitmap;
    }

    /**
     * Resolve the best value for inSampleSize attribute.
     *
     * @param ratio
     * @return
     */
    private static int getPowerOfTwoForSampleRatio(double ratio) {
        int k = Integer.highestOneBit((int) Math.floor(ratio));
        if (k == 0)
            return 1;
        else
            return k;
    }

    public static byte[] bitmapToBytes(Bitmap bmp) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
        byte[] array = stream.toByteArray();
        return array;
    }

    public static Bitmap bytesToBitmap(byte[] array) {
        if (array.length != 0) {
            return BitmapFactory.decodeByteArray(array, 0, array.length);
        } else {
            return null;
        }
    }

    /**
     * 将bitmap转换成base64字符串
     *
     * @param bitmap
     * @return base64 字符串
     */
    public static String bitmapToString(Bitmap bitmap, int bitmapQuality) {
        ByteArrayOutputStream bStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, bitmapQuality, bStream);
        byte[] bytes = bStream.toByteArray();
        String string = Base64.encodeToString(bytes, Base64.DEFAULT);
        return string;
    }

    /**
     * 将base64转换成bitmap图片
     *
     * @param string base64字符串
     * @return bitmap
     */
    public static Bitmap stringToBitmap(String string) {
        Bitmap bitmap = null;
        try {
            byte[] bitmapArray;
            bitmapArray = Base64.decode(string, Base64.DEFAULT);
            bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0,
                    bitmapArray.length);
        } catch (Exception e) {

        }
        return bitmap;
    }

    public static int dp2px(Context context, float dp) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }

    public static int px2dp(Context context, float px) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (px / scale + 0.5f);
    }

    /**
     * fuction: 设置固定的宽度，高度随之变化，使图片不会变形
     *
     * @param target   需要转化bitmap参数
     * @param newWidth 设置新的宽度
     * @return
     */
    public static Bitmap fitBitmap(Bitmap target, int newWidth) {
        int width = target.getWidth();
        int height = target.getHeight();
        Matrix matrix = new Matrix();
        float scaleWidth = ((float) newWidth) / width;
        // float scaleHeight = ((float)newHeight) / height;
        int newHeight = (int) (scaleWidth * height);
        matrix.postScale(scaleWidth, scaleWidth);
        // Bitmap result = Bitmap.createBitmap(target,0,0,width,height,
        // matrix,true);
        Bitmap bmp = Bitmap.createBitmap(target, 0, 0, width, height, matrix,
                true);
        if (target != null && !target.equals(bmp) && !target.isRecycled()) {
            target.recycle();
            target = null;
        }
        return bmp;// Bitmap.createBitmap(target, 0, 0, width, height, matrix,
        // true);
    }


    /**
     * 对从服务器请求的图片进行二次采样
     *
     * @param bitmap
     */

    public static Bitmap zoomBitmap(Bitmap bitmap, int width, int height) {

        if (bitmap != null) {
            int w = bitmap.getWidth();//获取图片的宽
            int h = bitmap.getHeight();//获取图片的高
            Matrix matrix = new Matrix();//创建矩阵对象
            float scaleWidth = ((float) width / w);//裁剪后的高
            float scaleHeight = ((float) height / h);//裁剪后的宽
            matrix.postScale(scaleWidth, scaleHeight);
            Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
//            if (bitmap != null && !bitmap.equals(newBitmap) && !bitmap.isRecycled()) {
//                bitmap.recycle();
//                bitmap = null;
//            }
            return newBitmap;
        }
        return null;
    }

    public static File saveBmpFile(Bitmap bitmap, String filename) {
        try {
            File file = new File(Environment.getExternalStorageDirectory(), filename);
            FileOutputStream fOut = new FileOutputStream(file);

            bitmap.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
            fOut.flush();
            fOut.close();
            return file;
        } catch (Exception e) {
            e.printStackTrace();
//            Log.e("BitmapUtil", "Save file error!");
        }

        bitmap.recycle();
        System.gc();
        return null;

    }

    /**
     * 根据给定的宽和高进行拉伸
     *
     * @param origin    原图
     * @param newWidth  新图的宽
     * @param newHeight 新图的高
     * @return new Bitmap
     */
    public static Bitmap scaleBitmap(Bitmap origin, int newWidth, int newHeight) {
        if (origin == null) {
            return null;
        }
        int height = origin.getHeight();
        int width = origin.getWidth();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);// 使用后乘
        Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
        if (!origin.isRecycled()) {
            origin.recycle();
        }
        return newBM;
    }

    /**
     * 根据给定的宽和高进行拉伸
     *
     * @param origin   原图
     * @param newWidth 新图的宽
     * @return new Bitmap
     */
    public static Bitmap scaleBitmapByWidth(Bitmap origin, int newWidth) {
        if (origin == null) {
            return null;
        }
        int height = origin.getHeight();
        int width = origin.getWidth();
        float scaleWidth = ((float) newWidth) / width;
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleWidth);// 使用后乘
        Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
        if (!origin.isRecycled()) {
            origin.recycle();
        }
        return newBM;
    }

    /**
     * 按比例缩放图片
     *
     * @param origin 原图
     * @param ratio  比例
     * @return 新的bitmap
     */
    public static Bitmap scaleBitmap(Bitmap origin, float ratio) {
        if (origin == null) {
            return null;
        }
        int width = origin.getWidth();
        int height = origin.getHeight();
        Matrix matrix = new Matrix();
        matrix.preScale(ratio, ratio);
        Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
        if (newBM.equals(origin)) {
            return newBM;
        }
        origin.recycle();
        return newBM;
    }

    /**
     * 裁剪
     *
     * @param bitmap 原图
     * @return 裁剪后的图像
     */
    public static Bitmap cropSquareBitmap(Bitmap bitmap) {
        int w = bitmap.getWidth(); // 得到图片的宽，高
        int h = bitmap.getHeight();
        int cropWidth = w >= h ? h : w;// 裁切后所取的正方形区域边长
        cropWidth /= 2;
        int cropHeight = (int) (cropWidth / 1.2);
        return Bitmap.createBitmap(bitmap, w / 3, 0, cropWidth, cropHeight, null, false);
    }

    /**
     * 选择变换
     *
     * @param origin 原图
     * @param alpha  旋转角度，可正可负
     * @return 旋转后的图片
     */
    public static Bitmap rotateBitmap(Bitmap origin, float alpha) {
        if (origin == null) {
            return null;
        }
        int width = origin.getWidth();
        int height = origin.getHeight();
        Matrix matrix = new Matrix();
        matrix.setRotate(alpha);
        // 围绕原地进行旋转
        Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
        if (newBM.equals(origin)) {
            return newBM;
        }
        origin.recycle();
        return newBM;
    }

    /**
     * 偏移效果
     *
     * @param origin 原图
     * @return 偏移后的bitmap
     */
    public static Bitmap skewBitmap(Bitmap origin) {
        if (origin == null) {
            return null;
        }
        int width = origin.getWidth();
        int height = origin.getHeight();
        Matrix matrix = new Matrix();
        matrix.postSkew(-0.6f, -0.3f);
        Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
        if (newBM.equals(origin)) {
            return newBM;
        }
        origin.recycle();
        return newBM;
    }

    /**
     * 图片合成
     *
     * @param background 底图
     * @param front      上层图片
     * @return
     */
    public static Bitmap composeBitmap(Bitmap background, Bitmap front, float alpha) {
        if (front == null) {
            return null;
        }
        int backgroundWidth = background.getWidth();
        int backgroundHeight = background.getHeight();
        int frontWidth = front.getWidth();
        int frontHeight = front.getHeight();
        //create the new blank bitmap
        Bitmap composeBitmap = Bitmap.createBitmap(backgroundWidth, backgroundHeight, Bitmap.Config.ARGB_8888);//创建一个新的和SRC长度宽度一样的位图
        Canvas canvas = new Canvas(composeBitmap);
        //draw src into
        Paint paint = new Paint();
        paint.setAlpha((int)(255 * alpha));
        canvas.drawBitmap(background, 0, 0, paint);//在 0，0坐标开始画入src
        //draw watermark into,*0.9f因为圆圈不在图
//        canvas.drawBitmap(front, (backgroundWidth - frontWidth) / 2, (deviat * backgroundHeight - frontHeight) / 2, null);
        if (frontHeight < backgroundHeight) {
            canvas.drawBitmap(front, (backgroundWidth - frontWidth) / 2, (backgroundHeight - frontHeight) / 2, paint);
        }
        //save all clip
        canvas.save(Canvas.ALL_SAVE_FLAG);//保存
        //store
        canvas.restore();//存储
        return composeBitmap;
    }

    /**
     * 图片合成
     *
     * @param backgroundResId 底图的资源ID
     * @param avatar          用户头像
     * @return
     */
    public static Bitmap composeBitmap(int backgroundResId, Bitmap avatar, int backgroundSize, int frontSize, float deviat) {
        if (avatar == null) {
            return null;
        }
        Bitmap background = scaleBitmapByWidth(BitmapFactory.decodeResource(GlobalContext.getGlobalContext().getResources(), backgroundResId), backgroundSize);
        Bitmap front = createCircleImage(zoomBitmap(avatar, frontSize, frontSize));
        return composeBitmap(background, front, deviat);
    }

    /**
     * 根据原图和变长绘制圆形图片
     *
     * @param source
     * @return
     */
    public static Bitmap createCircleImage(Bitmap source) {
        int sourceWidth = source.getWidth();
        int sourceHeight = source.getHeight();
        int min = sourceWidth > sourceHeight ? sourceHeight : sourceWidth;
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        Bitmap target = Bitmap.createBitmap(min, min, Bitmap.Config.ARGB_8888);
        /**
         * 产生一个同样大小的画布
         */
        Canvas canvas = new Canvas(target);
        /**
         * 首先绘制圆形
         */
        canvas.drawCircle(min / 2, min / 2, min / 2, paint);
        /**
         * 使用SRC_IN
         */
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        /**
         * 绘制图片
         */
        canvas.drawBitmap(source, 0, 0, paint);
        return target;
    }

    private static Bitmap decodeResource(Resources res, int id) {
        Bitmap bitmap = null;
        BitmapFactory.Options options = new BitmapFactory.Options();
        for (options.inSampleSize = 1; options.inSampleSize <= 32; options.inSampleSize++) {
            try {
                bitmap = BitmapFactory.decodeResource(res, id, options);
                L.d("Decoded successfully for sampleSize " + options.inSampleSize);
                break;
            } catch (OutOfMemoryError outOfMemoryError) {
                // If an OutOfMemoryError occurred, we continue with for loop and next inSampleSize value
                L.e("outOfMemoryError while reading file for sampleSize " + options.inSampleSize
                        + " retrying with higher value");
            }
        }
        return bitmap;
    }

    /**
     * 以最省内存的方式读取本地资源的图片
     *
     * @param context
     * @param resId
     * @return
     */
    public static Bitmap readBitMap(Context context, int resId) {
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPreferredConfig = Bitmap.Config.RGB_565;
        opt.inPurgeable = true;
        opt.inInputShareable = true;
        //获取资源图片
        InputStream is = context.getResources().openRawResource(resId);
        return BitmapFactory.decodeStream(is, null, opt);
    }

    public static int calculateInSampleSize(BitmapFactory.Options options,
                                            int reqWidth, int reqHeight) {
        // 源图片的高度和宽度
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            // 计算出实际宽高和目标宽高的比率
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            // 选择宽和高中最小的比率作为inSampleSize的值，这样可以保证最终图片的宽和高
            // 一定都会大于等于目标的宽和高。
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        return inSampleSize;
    }

    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
                                                         int reqWidth, int reqHeight) {
        // 第一次解析将inJustDecodeBounds设置为true，来获取图片大小
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);
        // 调用上面定义的方法计算inSampleSize值
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        // 使用获取到的inSampleSize值再次解析图片
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

    public static Bitmap compressBitmap(Bitmap image, int reqWidth, int reqHeight) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
        if (byteArrayOutputStream.toByteArray().length / 1024 > 1024) {//判断如果图片大于1M,进行压缩,避免在生成图片（BitmapFactory.decodeStream）时溢出
            byteArrayOutputStream.reset();//重置
            image.compress(Bitmap.CompressFormat.JPEG, 50, byteArrayOutputStream);//这里压缩50%
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(isBm, null, newOpts);
        isBm.reset();//一定要将流重置，否则输出为空
        newOpts.inSampleSize = calculateInSampleSize(newOpts, reqWidth, reqHeight);
        newOpts.inJustDecodeBounds = false;
        return BitmapFactory.decodeStream(isBm, null, newOpts);
    }

    /*根据屏幕大小改变图片尺寸，主要应用于发布活动或动态时图片剪裁功能
    *当bitmap的高度宽度都小于CropImageView的宽高，这样就会导致图片显示无法填充满屏幕。这也跟cropper的内部处理机制有关 */
    public static Bitmap getAdaptiveBitmap(Bitmap bitmap) {
        WindowManager wm = (WindowManager) GlobalContext.getGlobalContext().getSystemService(Context.WINDOW_SERVICE);
        //先获取屏幕宽高
        int width = wm.getDefaultDisplay().getWidth();
        int height = wm.getDefaultDisplay().getHeight();
        float scaleWidth = 1, scaleHeight = 1;
        if (bitmap.getWidth() < width) {
            //强转为float类型，
            scaleWidth = (float)width / (float)bitmap.getWidth();
        }
        if (bitmap.getHeight() < height) {
            scaleHeight = (float)height / (float)bitmap.getHeight();
        }
        if (scaleWidth > scaleHeight)
            scaleHeight = scaleWidth;
        else
            scaleWidth = scaleHeight;
        Matrix matrix = new Matrix();
        //根据屏幕大小选择bitmap放大比例。
        matrix.postScale(scaleWidth, scaleHeight);
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight()
                , matrix, true);
        return bitmap;
    }
}
